﻿using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using NodeBasedSkillEditor.ViewModel;

namespace NodeBasedSkillEditor.View
{
    public class LinkControl : Control
    {
        private SolidColorBrush _lineColor = new SolidColorBrush(Color.FromRgb(192, 192, 192));
        public SolidColorBrush LineColor {
            get { return _lineColor; }
            set { _lineColor = value; InvalidateVisual(); }
        }

        public double LineWidth {
            get { return (double)GetValue(LineWidthProperty); }
            set { SetValue(LineWidthProperty, value); }
        }
        public static readonly DependencyProperty LineWidthProperty =
            DependencyProperty.Register("LineWidth", typeof(double), typeof(LinkControl),
                new PropertyMetadata(2.0, OnLineWidthChanged));

        private static void OnLineWidthChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var ctrl = d as LinkControl;
            ctrl.InvalidateVisual();
        }

        private Point _startPoint;
        public Point StartPoint {
            get { return _startPoint; }
            set { _startPoint = value; InvalidateVisual(); }
        }

        private Point _endPoint;
        public Point EndPoint {
            get { return _endPoint; }
            set { _endPoint = value; InvalidateVisual(); }
        }

        private bool _isValid = true;

        public bool IsValid {
            get { return _isValid; }
            set { _isValid = value; InvalidateVisual(); }
        }


        private VM_Port _fromPort;
        public VM_Port FromPort {
            get { return _fromPort; }
            set {
                if (_fromPort != null)
                {
                    _fromPort.ParentNode.OnPortPositionChanged -= OnLinkedPortPositionChanged;
                    _fromPort.OnPortColorChanged -= ChangeColor;
                }
                _fromPort = value;
                if (_fromPort != null)
                {
                    _fromPort.ParentNode.OnPortPositionChanged += OnLinkedPortPositionChanged;
                    _fromPort.OnPortColorChanged += ChangeColor;
                }
                LineColor.Color = DAGHelper.GetColorFromDataType(_fromPort?.DataType);
                InvalidateVisual();
            }
        }

        private VM_Port _toPort;
        public VM_Port ToPort {
            get { return _toPort; }
            set {
                if (_toPort != null)
                {
                    _toPort.ParentNode.OnPortPositionChanged -= OnLinkedPortPositionChanged;
                }
                _toPort = value;
                if (_toPort != null)
                {
                    _toPort.ParentNode.OnPortPositionChanged += OnLinkedPortPositionChanged;
                }
                InvalidateVisual();
            }
        }

        public event Action<MouseButtonEventArgs, LinkControl> OnLMBDownOnLink;

        static LinkControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(LinkControl), new FrameworkPropertyMetadata(typeof(LinkControl)));
        }

        public LinkControl()
        {
            Panel.SetZIndex(this, -1);
        }

        public LinkControl(VM_Port fromPort, VM_Port toPort)
        {
            Panel.SetZIndex(this, -1);

            FromPort = fromPort;
            ToPort = toPort;
        }

        ~LinkControl()
        {
            ClearPortListoner();
        }

        public void ClearPortListoner()
        {
            if (FromPort != null)
            {
                FromPort.ParentNode.OnPortPositionChanged -= OnLinkedPortPositionChanged;
                FromPort.OnPortColorChanged -= ChangeColor;
            }
            if (ToPort != null)
            {
                ToPort.ParentNode.OnPortPositionChanged -= OnLinkedPortPositionChanged;
            }
        }

        void OnLinkedPortPositionChanged()
        {
            InvalidateVisual();
        }

        public void ChangeColor(Color newColor)
        {
            LineColor.Color = newColor;
            InvalidateVisual();
        }

        void OnFromPortColorChanged(Color newColor)
        {
            LineColor.Color = newColor;
            InvalidateVisual();
        }

        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        {
            OnLMBDownOnLink?.Invoke(e, this);
        }

        protected override void OnRender(DrawingContext drawingContext)
        {
            base.OnRender(drawingContext);
            DrawCurve(drawingContext);
        }

        void DrawCurve(DrawingContext dc)
        {
            if (FromPort != null)
            {
                StartPoint = FromPort.Position;
            }

            if (ToPort != null)
            {
                EndPoint = ToPort.Position;
            }

            var horiLength = Math.Abs(Math.Max(EndPoint.X - StartPoint.X, -180));

            var horiSlopeLen = Math.Max(horiLength * 0.33, 20);

            var slope1 = new Point(StartPoint.X + horiSlopeLen, StartPoint.Y);
            var slope2 = new Point(EndPoint.X - horiSlopeLen, EndPoint.Y);

            var pathStream = new StreamGeometry();

            using (var context = pathStream.Open())
            {
                context.BeginFigure(StartPoint, true, false);
                context.BezierTo(slope1, slope2, EndPoint, true, false);
            }
            pathStream.Freeze();

            var pen = new Pen(LineColor, LineWidth);
            if (!IsValid)
            {
                pen.DashStyle = new DashStyle(new double[] { 0, 3 }, 0);
            }
            dc.DrawGeometry(null, pen, pathStream);
        }
    }
}
